home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr47
/
wasm223.zip
/
MACRO1.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-05-04
|
44KB
|
1,750 lines
;***************************************;
; WASM Macro Processor, Compile and Run ;
; By Eric Tauck ;
; ;
; Defines: ;
; ;
; MacAll allocate macro buffers ;
; MacRel release macro buffers ;
; MacCom load and compile a macro ;
; MacRes reset macro execution ;
; MacRun run currently loaded macro ;
; MacAdr return address of symbol ;
; MacLoa load a stack item ;
; MacSto store a stack item ;
; MacBug debug flag ;
; ;
; Requires: ;
; ;
; BUFFER1.ASM ;
; BUFFER2.ASM ;
; BUFFER4.ASM ;
; CONVERT.ASM ;
; MEMORY.ASM ;
; STACK.ASM ;
; STRING.ASM ;
;***************************************;
jmp _macro1_end
MACRO_TOKEN EQU 33 ;maximum token size (32 characters plus NUL)
_mac_level DW 0 ;INCLUDE nest level
;--- error result codes
MACRO_MEMORY EQU 1 ;not enough memory
MACRO_SYMBOL EQU 2 ;out of symbol memory
MACRO_CODE EQU 3 ;out of code memory
MACRO_LONGTOK EQU 4 ;token too long
MACRO_UNDEF EQU 5 ;undefined symbol
MACRO_BADEOF EQU 6 ;unexpected EOF after : { " ALLOC INCLUDE
MACRO_FILE EQU 7 ;error reading file
MACRO_BADNUM EQU 8 ;invalid number after ALLOC
;--- table segment
_mac_symsiz DW ? ;size
_mac_symseg DW 0 ;segment
_mac_symptr DW ? ;symbol pointer (grows up from beginning)
_mac_fixptr DW ? ;fixup pointer (grows down from end)
;--- code segment
_mac_codsiz DW ? ;size
_mac_start LABEL DWORD
DW 0 ;-- code entry point
_mac_codseg DW ? ;segment ;
_mac_codptr DW ? ;code pointer
;--- stack segment
_mac_stksiz DW ? ;size
_mac_stkseg DW ? ;segment
;--- saved state
_mac_codsav DW ? ;current location
_mac_retsav DW ? ;return pointer
_mac_stksav DW ? ;stack offset
_mac_stksav2 DW ? ;saved stack offset during external call
;--- debugging info
MacBug DB 0 ;symbol table save flag (non-zero if save)
_mac_undlen DW 0 ;length of undefined symbol
_mac_undoff DW 0 ;offset of undefined symbol
;--- built in words
_mac_Compiled LABEL BYTE
DB ':', 0, OFFSET _mac_Define
DB '"', 0, OFFSET _mac_String
DB '{', 0, OFFSET _mac_Inline
DB '//', 0, OFFSET _mac_Comment
DB 'HERE', 0, OFFSET _mac_HERE
DB 'ALLOC', 0, OFFSET _mac_ALLOC
DB 'INCLUDE', 0, OFFSET _mac_INCLUDE
DB 0
_mac_Standard LABEL BYTE
DB ';', 0, OFFSET _mac_Return
DB '!', 0, OFFSET _mac_Store
DB '@', 0, OFFSET _mac_Fetch
DB '+', 0, OFFSET _mac_Add
DB '-', 0, OFFSET _mac_Subtract
DB '*', 0, OFFSET _mac_Multiply
DB '/', 0, OFFSET _mac_Divide
DB 'MOD',0, OFFSET _mac_MOD
DB '/MOD',0, OFFSET _mac_dMOD
DB 'MIN',0, OFFSET _mac_MIN
DB 'MAX',0, OFFSET _mac_MAX
DB 'NEGATE',0, OFFSET _mac_NEGATE
DB 'ABS',0, OFFSET _mac_ABS
DB '1+',0, OFFSET _mac_1Add
DB '2+',0, OFFSET _mac_2Add
DB '1-',0, OFFSET _mac_1Subtract
DB '2-',0, OFFSET _mac_2Subtract
DB '2*',0, OFFSET _mac_2Multiply
DB '2/',0, OFFSET _mac_2Divide
DB 'DUP',0, OFFSET _mac_DUP
DB '?DUP',0, OFFSET _mac_qDUP
DB 'DROP',0, OFFSET _mac_DROP
DB 'SWAP',0, OFFSET _mac_SWAP
DB 'OVER',0, OFFSET _mac_OVER
DB 'PICK',0, OFFSET _mac_PICK
DB 'ROT',0, OFFSET _mac_ROT
DB '=',0, OFFSET _mac_Equal
DB '>',0, OFFSET _mac_Greater
DB '<',0, OFFSET _mac_Less
DB '0=',0, OFFSET _mac_ZeroEqual
DB '0>',0, OFFSET _mac_ZeroGreater
DB '0<',0, OFFSET _mac_ZeroLess
DB 'FALSE',0, OFFSET _mac_FALSE
DB 'TRUE',0, OFFSET _mac_TRUE
DB 'AND',0, OFFSET _mac_AND
DB 'OR',0, OFFSET _mac_OR
DB 'NOT',0, OFFSET _mac_NOT
DB 'JUMP', 0, OFFSET _mac_JUMP
DB '?JUMP', 0, OFFSET _mac_qJUMP
DB 'CALL', 0, OFFSET _mac_CALL
DB '?CALL', 0, OFFSET _mac_qCALL
DB 'BREAK', 0, OFFSET _mac_BREAK
DB 'QUIT', 0, OFFSET _mac_QUIT
DB 0
;========================================
; Determine symbol table bytes available.
;
; Out: AX= bytes available.
_mac_SymAvail PROC NEAR
mov ax, _mac_fixptr ;fixup pointer
sub ax, _mac_symptr ;symbol pointer
ret
ENDP
;========================================
; Store a symbol.
;
; In: SI= symbol; AX= address of symbol.
;
; Out: CY= set if error.
_mac_Symbol PROC NEAR
push di
push si
;--- check if space is available
push ax
mov ax, si
call StrLen ;get string length
push ax
call _mac_SymAvail ;get bytes available
pop cx
pop dx
mov bx, 3
sub ax, bx ;reduce of length and data
jc _mcssy1
cmp ax, cx ;check if room for symbol
jb _mcssy1
;--- store symbol and its data
cld
mov di, _mac_symptr ;pointer
add bx, cx
add bx, di ;new pointer address
mov _mac_symptr, bx ;save updated pointer
push es
mov ax, _mac_symseg ;segment
mov es, ax ;new data segment
mov al, cl
stosb ;store length
rep
movsb ;copy symbol
mov ax, dx
stosw ;store data
pop es
pop si
pop di
clc
ret
;--- out of symbol space
_mcssy1 mov ax, MACRO_SYMBOL
pop si
pop di
stc
ret
ENDP
;========================================
; Store a fixup.
;
; In: SI= symbol; AX= address of fixup.
;
; Out: CY= set if error.
_mac_Fixup PROC NEAR
push di
push si
;--- check if space is available
push ax
mov ax, si
call StrLen ;get string length
push ax
call _mac_SymAvail ;get bytes available
pop cx
pop dx
mov bx, 3
sub ax, bx ;reduce of length and data
jc _mcfix1
cmp ax, cx ;check if room for symbol
jb _mcfix1
;--- store symbol and its data
cld
mov di, _mac_fixptr ;pointer
add bx, cx
sub di, bx ;new pointer
mov _mac_fixptr, di ;save updated pointer
push es
mov ax, _mac_symseg ;segment
mov es, ax ;new data segment
mov ax, dx
stosw ;store data
mov al, cl ;length
rep
movsb ;copy symbol
stosb ;store length
pop es
pop si
pop di
clc
ret
;--- out of symbol space
_mcfix1 mov ax, MACRO_SYMBOL
pop si
pop di
stc
ret
ENDP
;========================================
; Look up the address of a symbol.
;
; In: AX= symbol.
;
; Out: AX= address; CY= set if not found
; (or no symbol table).
MacAdr PROC NEAR
push di
push si
push ds
mov di, ax
call StrLen ;get symbol length
mov cx, ax ;save length
mov ax, _mac_symseg ;load segment
or ax, ax ;check if any
jz _mcadr3 ;exit if not
cld
mov ds, ax ;symbol table segment
sub si, si ;symbol table offset
jmps _mcadr2
;--- loop for each symbol in table
_mcadr1 sub ah, ah ;AX has length
inc ax ;
inc ax ;skip address
add si, ax ;next symbol
_mcadr2 seg es
cmp si, _mac_symptr ;check if end
je _mcadr3 ;jump if so, not found
lodsb ;load length
cmp al, cl ;check if length matches
jne _mcadr1 ;loop back if not
push cx
push di
push si
rep
cmpsb ;compare strings
mov dx, [si] ;load address if match
pop si
pop di
pop cx
jne _mcadr1 ;loop back if different
;--- symbol found, return address
mov ax, dx
pop ds
pop si
pop di
clc
ret
;---- symbol not found
_mcadr3 pop ds
pop si
pop di
stc
ret
ENDP
;========================================
; Process all fixups.
;
; Out: CY= set if error.
_mac_Fixups PROC NEAR
push di
push si
StkAll di, MACRO_TOKEN
mov si, _mac_symsiz ;start of fixups
jmps _mcfxs2 ;enter loop
;--- get next fixup
_mcfxs1 push di
push ds
mov ax, _mac_symseg
mov ds, ax
dec si ;point to length byte
mov cl, [si] ;length of fixup symbol
sub ch, ch
sub si, cx ;start of fixup symbol
push cx
push si
cld
rep
movsb ;copy to local storage
sub al, al ;zero
stosb ;store NUL
pop si
pop cx
mov ax, [si-2] ;load fixup address
pop ds
pop di
mov _mac_undlen, cx ;save length of symbol
mov _mac_undoff, si ;save offset of symbol
;--- look up symbol
push ax
mov ax, di
call MacAdr ;loop up symbol
pop bx
jc _mcfxs3 ;exit if not found
;--- found symbol
push ds
mov dx, _mac_codseg ;load load code segment
mov ds, dx ;
mov [bx], ax ;save fixup
pop ds
dec si ;next fixup symbol
dec si ;
;--- next fixup
_mcfxs2 cmp si, _mac_fixptr ;check if finished
jne _mcfxs1
StkRel MACRO_TOKEN ;fix stack
pop si
pop di
clc
ret
;--- undefined symbol
_mcfxs3 mov ax, MACRO_UNDEF ;return error
StkRel MACRO_TOKEN ;fix stack
pop si
pop di
stc
ret
ENDP
;========================================
; Determine code table bytes available.
;
; Out: AX= bytes available.
_mac_CodAvail PROC NEAR
mov ax, _mac_codsiz ;return pointer
sub ax, _mac_codptr ;code pointer
ret
ENDP
;========================================
; Store a byte to the code table.
;
; In: AL= byte.
;
; Out: CY= set if error.
_mac_CodeB PROC NEAR
push ax
call _mac_CodAvail ;get bytes available
pop dx
or ax, ax ;check if any
jz _mccob1
push ds
mov bx, _mac_codptr ;load code pointer
mov ds, _mac_codseg
mov [bx], dl ;store byte
pop ds
inc _mac_codptr ;increment pointer
clc
ret
;--- error, out of memory
_mccob1 mov al, MACRO_CODE ;result code
stc
ret
ENDP
;========================================
; Store a word to the code table.
;
; In: AL= byte.
;
; Out: CY= set if error.
_mac_CodeW PROC NEAR
push ax
call _mac_CodeB ;store low byte
pop ax
jc _mccow1
mov al, ah
call _mac_CodeB ;store high byte
_mccow1 ret
ENDP
;========================================
; Store a code routine.
;
; In: AX= address of routine.
;
; Out: CY= set if error.
_mac_Code PROC NEAR
push si
mov si, ax
mov cx, [si] ;load size of code
inc si ;
inc si ;skip length
_mccod1 cld
lodsb ;load byte
push cx
call _mac_CodeB ;store byte
pop cx
jc _mccod2 ;exit if error
loop _mccod1 ;loop for each byte
_mccod2 pop si
ret
ENDP
;========================================
; Search for a symbol.
;
; In: SI= symbol; AX= symbol table.
;
; Out: CY= cleared if found; AX= data.
_mac_Search PROC NEAR
push di
mov di, ax
jmps _mcsea2
;--- skip of reset of table entry
_mcsea1 sub al, al ;search for NUL
cld
mov cx, 0FFFFH
repne
scasb ;scan
inc di
inc di ;skip rest of value
;--- compare entry
_mcsea2 cmp BYTE [di], 0 ;check if end of table
je _mcsea5 ;exit if so
sub bx, bx ;zero index
jmps _mcsea4
;--- loop for each character
_mcsea3 inc di ;increment table pointer
inc bx ;increment index
_mcsea4 mov al, [si+bx] ;load source character
cmp al, [di] ;check if match
jne _mcsea1 ;goto next entry if not
or al, al ;check if end of strings
jnz _mcsea3 ;loop back if not
;--- found
mov ax, [di+1] ;load table value
pop di
clc
ret
;--- not found
_mcsea5 pop di
stc
ret
ENDP
;========================================
; Compiled words.
;=== define a symbol
_mac_Define PROC NEAR
mov ax, si
mov cx, MACRO_TOKEN
mov bx, di
call GetTok ;get symbol
jc _mcdef1 ;exit if error
or ax, ax ;check if EOF
jz _mcdef3 ;exit if so
mov ax, _mac_codptr ;address
call _mac_Symbol ;put in symbol table
ret
;--- error reading token
_mcdef1 or ax, ax ;check if DOS error
jnz _mcdef2 ;jump if so
mov ax, MACRO_LONGTOK
stc
ret
_mcdef2 mov ax, MACRO_FILE
stc
ret
_mcdef3 mov ax, MACRO_BADEOF
stc
ret
ENDP
;=== store a string
_mac_String PROC NEAR
jmps _mcstr2
_mcstr1 call _mac_CodeB ;store byte
jc _mcstr3 ;exit if error
_mcstr2 mov bx, di
call GetByt ;get a byte
jc _mcstr6
cmp al, 32 ;check if delimiter
jb _mcstr2
cmp al, '^' ;check if control character
je _mcstr4
cmp al, '\' ;check if mask character
je _mcstr5
cmp al, '"' ;check if end of string
jne _mcstr1
sub al, al ;NUL
call _mac_CodeB ;store byte
_mcstr3 ret
;--- control character
_mcstr4 mov bx, di
call GetByt ;get byte
jc _mcstr6
call ChrUpr ;convert to uppercase
sub al, 64 ;translate to control code
jmps _mcstr1
;--- mask character
_mcstr5 mov bx, di
call GetByt ;get byte
jnc _mcstr1
;--- error reading byte
_mcstr6 or al, al ;check if DOS error
jnz _mcstr7 ;jump if so
mov ax, MACRO_BADEOF
stc
ret
_mcstr7 mov ax, MACRO_FILE
stc
ret
ENDP
;=== inline code
_mac_Inline PROC NEAR
;--- loop for each token in { }
_mcinl1 mov ax, si
mov cx, MACRO_TOKEN
mov bx, di
call GetTok ;get data
jc _mcinl4 ;exit if error
or ax, ax ;check if EOF
jz _mcinl6 ;exit if so
cmp WORD [si],007DH ;check if end of data: '}',0
je _mcinl3 ;exit loop if so
;--- check if number
call _mac_GetNumber ;interpret as number
jnc _mcinl2 ;jump if okay
;--- must be symbol reference
mov ax, _mac_codptr
call _mac_Fixup ;store fixup
sub ax, ax
_mcinl2 call _mac_CodeW ;code a word
jnc _mcinl1 ;loop back if no error
_mcinl3 ret
;--- error
_mcinl4 or ax, ax ;check if DOS error
jnz _mcinl5 ;jump if so
mov ax, MACRO_LONGTOK
stc
ret
_mcinl5 mov ax, MACRO_FILE
stc
ret
_mcinl6 mov ax, MACRO_BADEOF
stc
ret
ENDP
;=== skip a comment
_mac_Comment PROC NEAR
_mccmm1 mov bx, di
call GetByt ;get a byte
jc _mccmm3 ;jump if error
cmp al, 13 ;check if CR
je _mccmm2
cmp al, 10 ;check if LF
jne _mccmm1
_mccmm2 clc
ret
;--- error reading byte
_mccmm3 or al, al ;check if DOS error
jz _mccmm2 ;jump if EOF, no error
mov ax, MACRO_FILE
stc
ret
ENDP
;=== push current address
_mac_HERE PROC NEAR
mov ax, _mac_codptr ;current location
add ax, 4 ;skip the HERE code
call _mac_Number ;push a number
ret
ENDP
;=== allocate space
_mac_ALLOC PROC NEAR
mov ax, si
mov cx, MACRO_TOKEN
mov bx, di
call GetTok ;get amount of space
jc _mcalc4 ;exit if error
or ax, ax ;check if EOF
jz _mcalc6 ;exit if so
call _mac_GetNumber ;interpret number
jc _mcalc7 ;jump if error
;--- store bytes of code
mov cx, ax
jcxz _mcalc2 ;exit if no bytes
_mcalc1 push cx
sub al, al
call _mac_CodeB ;store a zero
pop cx
jc _mcalc3 ;exit if error
loop _mcalc1 ;loop for all bytes
_mcalc2 clc
_mcalc3 ret
;--- error reading token
_mcalc4 or ax, ax ;check if DOS error
jnz _mcalc5 ;jump if so
mov ax, MACRO_LONGTOK
stc
ret
_mcalc5 mov ax, MACRO_FILE
stc
ret
_mcalc6 mov ax, MACRO_BADEOF
stc
ret
_mcalc7 mov ax, MACRO_BADNUM
stc
ret
ENDP
;=== include file
_mac_INCLUDE PROC NEAR
mov ax, si
mov cx, MACRO_TOKEN
mov bx, di
call GetTok ;get data
jc _mcinc1 ;exit if error
or ax, ax ;check if EOF
jz _mcinc3 ;exit if so
mov ax, si
inc _mac_level
call MacCom ;compile without initialization
dec _mac_level
ret
;--- error
_mcinc1 or ax, ax ;check if DOS error
jnz _mcinc2 ;jump if so
mov ax, MACRO_LONGTOK
stc
ret
_mcinc2 mov ax, MACRO_FILE
stc
ret
_mcinc3 mov ax, MACRO_BADEOF
stc
ret
ENDP
;=== push a number, In: AX= number
_mac_Number PROC NEAR
mov [OFFSET _mac_Load + 3], ax
mov ax, OFFSET _mac_Load
call _mac_Code
ret
ENDP
;=== push a symbol address
_mac_Reference PROC NEAR
call _mac_Number
mov ax, _mac_codptr
sub ax, 3
call _mac_Fixup
ret
ENDP
;=== external symbol reference
_mac_External PROC NEAR
mov [OFFSET _mac_LongCall + 3], ax
mov ax, OFFSET _mac_LongCall
call _mac_Code
ret
ENDP
;========================================
; Standard words.
;=== startup code
_mac_Startup
DW OFFSET _mac_Startupx - OFFSET _mac_Startup - 2
_mcsta1 EQU $
ORG 0
;--- entry code, expects real start address in AX
pop dx
mov [_mcrets], dx
pop dx
mov [_mcreto], dx
push ax
retn
;--- external hook routine, expects external address in DX:AX
_mccal mov WORD _mcextr, ax ;save target address
mov WORD _mcextr + 2, dx ;
push es ;load data segment
pop ds ;
mov _mac_stksav2, sp ;save stack offset
cli
mov ax, _mac_oldseg
mov ss, ax
mov sp, _mac_oldoff
sti
seg cs
call _mcextr ;call external routine
cli
mov ax, _mac_stkseg
mov ss, ax
mov sp, _mac_stksav2
sti
push cs ;
pop ds ;reload data segment
retn
;--- data
_mcrets DW 0 ;return segment
_mcreto DW 0 ;return offset
_mcextr LABEL DWORD ;external routine location
DW 0, 0
_mcstar ORG $ + _mcsta1
_mac_Startupx
;=== load a number to the stack, the number must be set
_mac_Load
DW OFFSET _mac_Loadx - OFFSET _mac_Load - 2
mov ax, 0
push ax
_mac_Loadx
;=== call an externl routine, the offset and segment must be set
_mac_LongCall
DW OFFSET _mac_LongCallx - OFFSET _mac_LongCall - 2
mov ax, 0
mov dx, es
mov bx, OFFSET _mccal
call bx
_mac_LongCallx
;=== return from a routine
_mac_Return
DW OFFSET _mac_Returnx - OFFSET _mac_Return - 2
inc si
inc si
jmp WORD [si]
_mac_Returnx
;=== store a value to an address
_mac_Store
DW OFFSET _mac_Storex - OFFSET _mac_Store - 2
pop bx
pop ax
mov [bx], ax
_mac_Storex
;=== load a number from an address
_mac_Fetch
DW OFFSET _mac_Fetchx - OFFSET _mac_Fetch - 2
pop bx
push WORD [bx]
_mac_Fetchx
;=== add two numbers
_mac_Add
DW OFFSET _mac_Addx - OFFSET _mac_Add - 2
pop bx
pop ax
add ax, bx
push ax
_mac_Addx
;=== subtract two numbers
_mac_Subtract
DW OFFSET _mac_Subtractx - OFFSET _mac_Subtract - 2
pop bx
pop ax
sub ax, bx
push ax
_mac_Subtractx
;=== multiply two numbers
_mac_Multiply
DW OFFSET _mac_Multiplyx - OFFSET _mac_Multiply - 2
pop ax
pop dx
imul ax, dx
push ax
_mac_Multiplyx
;=== divide two numbers
_mac_Divide
DW OFFSET _mac_Dividex - OFFSET _mac_Divide - 2
pop bx
pop ax
sub dx, dx
idiv ax, bx
push ax
_mac_Dividex
;=== divide two numbers, return only remainder
_mac_MOD
DW OFFSET _mac_MODx - OFFSET _mac_MOD - 2
pop bx
pop ax
sub dx, dx
idiv ax, bx
push dx
_mac_MODx
;=== divide two numbers, return quotient and remainder
_mac_dMOD
DW OFFSET _mac_dMODx - OFFSET _mac_dMOD - 2
pop bx
pop ax
sub dx, dx
idiv ax, bx
push dx
push ax
_mac_dMODx
;=== return minimum of two numbers
_mac_MIN
DW OFFSET _mac_MINx - OFFSET _mac_MIN - 2
pop ax
pop dx
cmp ax, dx
jle _mcmin1
mov ax, dx
_mcmin1 push ax
_mac_MINx
;=== return the maximum of two numbers
_mac_MAX
DW OFFSET _mac_MAXx - OFFSET _mac_MAX - 2
pop ax
pop dx
cmp ax, dx
jge _mcmax1
mov ax, dx
_mcmax1 push ax
_mac_MAXx
;=== negate a number
_mac_NEGATE
DW OFFSET _mac_NEGATEx - OFFSET _mac_NEGATE - 2
pop ax
neg ax
push ax
_mac_NEGATEx
;=== return the absolute value of a number
_mac_ABS
DW OFFSET _mac_ABSx - OFFSET _mac_ABS - 2
pop ax
cmp ax, 0
jge _mcabs1
neg ax
_mcabs1 push ax
_mac_ABSx
;=== increment a number
_mac_1Add
DW OFFSET _mac_1Addx - OFFSET _mac_1Add - 2
pop ax
inc ax
push ax
_mac_1Addx
;=== add two to a number
_mac_2Add
DW OFFSET _mac_2Addx - OFFSET _mac_2Add - 2
pop ax
inc ax
inc ax
push ax
_mac_2Addx
;=== decrement a number
_mac_1Subtract
DW OFFSET _mac_1Subtractx - OFFSET _mac_1Subtract - 2
pop ax
dec ax
push ax
_mac_1Subtractx
;=== subtract two from a number
_mac_2Subtract
DW OFFSET _mac_2Subtractx - OFFSET _mac_2Subtract - 2
pop ax
dec ax
dec ax
push ax
_mac_2Subtractx
;=== multiply a number times two
_mac_2Multiply
DW OFFSET _mac_2Multiplyx - OFFSET _mac_2Multiply - 2
pop ax
shl ax
push ax
_mac_2Multiplyx
;=== divide a number by two
_mac_2Divide
DW OFFSET _mac_2Dividex - OFFSET _mac_2Divide - 2
pop ax
shr ax
push ax
_mac_2Dividex
;=== duplicate an item
_mac_DUP
DW OFFSET _mac_DUPx - OFFSET _mac_DUP - 2
pop ax
push ax
push ax
_mac_DUPx
;=== duplicate an item if non-zero
_mac_qDUP
DW OFFSET _mac_qDUPx - OFFSET _mac_qDUP - 2
pop ax
or ax, ax
jz _mcqdu1
push ax
_mcqdu1 push ax
_mac_qDUPx
;=== drop an item
_mac_DROP
DW OFFSET _mac_DROPx - OFFSET _mac_DROP - 2
pop ax
_mac_DROPx
;=== swap top two items
_mac_SWAP
DW OFFSET _mac_SWAPx - OFFSET _mac_SWAP - 2
pop ax
pop dx
push ax
push dx
_mac_SWAPx
;=== copy second item down to top of stack
_mac_OVER
DW OFFSET _mac_OVERx - OFFSET _mac_OVER - 2
pop ax
pop dx
push ax
push dx
push ax
_mac_OVERx
;=== copy an indexed item down to the the top of the stack
_mac_PICK
DW OFFSET _mac_PICKx - OFFSET _mac_PICK - 2
pop di
shl di
mov bp, sp
push WORD [bp + di]
_mac_PICKx
;=== rotate top three items
_mac_ROT
DW OFFSET _mac_ROTx - OFFSET _mac_ROT - 2
pop ax
pop bx
pop cx
push bx
push ax
push cx
_mac_ROTx
;=== check if a number is equal to another number
_mac_Equal
DW OFFSET _mac_Equalx - OFFSET _mac_Equal - 2
pop ax
pop dx
sub bx, bx
cmp ax, dx
jne _mcequ1
dec bx
_mcequ1 push bx
_mac_Equalx
;=== check if a number is greater than another number
_mac_Greater
DW OFFSET _mac_Greaterx - OFFSET _mac_Greater - 2
pop ax
pop dx
sub bx, bx
cmp dx, ax
jle _mcgre1
dec bx
_mcgre1 push bx
_mac_Greaterx
;=== check if a number is less than another number
_mac_Less
DW OFFSET _mac_Lessx - OFFSET _mac_Less - 2
pop ax
pop dx
sub bx, bx
cmp dx, ax
jge _mcles1
dec bx
_mcles1 push bx
_mac_Lessx
;=== check if a number is equal to zero
_mac_ZeroEqual
DW OFFSET _mac_ZeroEqualx - OFFSET _mac_ZeroEqual - 2
pop ax
sub bx, bx
or ax, ax
jnz _mczeq1
dec bx
_mczeq1 push bx
_mac_ZeroEqualx
;=== check if a number is greater than zero
_mac_ZeroGreater
DW OFFSET _mac_ZeroGreaterx - OFFSET _mac_ZeroGreater - 2
pop ax
sub bx, bx
cmp ax, 0
jle _mczgr1
dec bx
_mczgr1 push bx
_mac_ZeroGreaterx
;=== check if a number is less than zero
_mac_ZeroLess
DW OFFSET _mac_ZeroLessx - OFFSET _mac_ZeroLess - 2
pop ax
sub bx, bx
cmp ax, 0
jge _mczle1
dec bx
_mczle1 push bx
_mac_ZeroLessx
;=== load FALSE (zero)
_mac_FALSE
DW OFFSET _mac_FALSEx - OFFSET _mac_FALSE - 2
sub ax, ax
push ax
_mac_FALSEx
;=== load TRUE ($FFFF)
_mac_TRUE
DW OFFSET _mac_TRUEx - OFFSET _mac_TRUE - 2
mov ax, -1
push ax
_mac_TRUEx
;=== AND two numbers
_mac_AND
DW OFFSET _mac_ANDx - OFFSET _mac_AND - 2
pop ax
pop dx
and ax, dx
push ax
_mac_ANDx
;=== OR two numbers
_mac_OR
DW OFFSET _mac_ORx - OFFSET _mac_OR - 2
pop ax
pop dx
or ax, dx
push ax
_mac_ORx
;=== NOT a number
_mac_NOT
DW OFFSET _mac_NOTx - OFFSET _mac_NOT - 2
pop ax
not ax
push ax
_mac_NOTx
;=== jump to an address
_mac_JUMP
DW OFFSET _mac_JUMPx - OFFSET _mac_JUMP - 2
retn
_mac_JUMPx
;=== jump to an address if condition is true
_mac_qJUMP
DW OFFSET _mac_qJUMPx - OFFSET _mac_qJUMP - 2
pop dx
pop ax
or ax, ax
jz _mac_qJUMPx
jmp dx
_mac_qJUMPx
;=== call a routine
_mac_CALL
DW OFFSET _mac_CALLx - OFFSET _mac_CALL - 2
call _mccal1
_mccal1 pop ax
add ax, OFFSET _mac_CALLx - OFFSET _mccal1
mov [si], ax
dec si
dec si
retn
_mac_CALLx
;=== call a routine if a contition is true
_mac_qCALL
DW OFFSET _mac_qCALLx - OFFSET _mac_qCALL - 2
pop dx
pop ax
or ax, ax
jz _mac_qCALLx
call _mcqca1
_mcqca1 pop ax
add ax, OFFSET _mac_qCALLx - OFFSET _mcqca1
mov [si], ax
dec si
dec si
jmp dx
_mac_qCALLx
;=== break into a macro
_mac_BREAK
DW OFFSET _mac_BREAKx - OFFSET _mac_BREAK - 2
push WORD [_mcreto]
push WORD [_mcrets]
call _mcbrk1
_mcbrk1 pop ax
add ax, 6
stc
retf
_mac_BREAKx
;=== quit a macro
_mac_QUIT
DW OFFSET _mac_QUITx - OFFSET _mac_QUIT - 2
push WORD [_mcreto]
push WORD [_mcrets]
clc
retf
_mac_QUITx
;========================================
; Try to translate token into number.
;
; In: SI= token buffer.
;
; Out: CY= clear if number; AX= value.
_mac_GetNumber PROC NEAR
;=== check if quoted character
cmp BYTE [si], 39
jne _mcgnu1
cmp BYTE [si+1], 0
je _mcgnu1
cmp BYTE [si+2], 39
jne _mcgnu1
cmp BYTE [si+3], 0
jne _mcgnu1
mov al, [si+1]
sub ah, ah
clc
ret
;=== check if number
;--- sign
_mcgnu1 push si
cmp BYTE [si], '+' ;check if plus
je _mcgnu2
cmp BYTE [si], '-' ;check if minus
jne _mcgnu3
_mcgnu2 inc si ;skip sign
;--- hex / decimal
_mcgnu3 mov cx, 10 ;base 10
cmp BYTE [si], '$' ;check if hex number
jne _mcgnu4 ;skip if not
mov cx, 16 ;base 16
inc si ;skip $
;--- convert number
_mcgnu4 mov ax, si
call Str2Num ;convert to number
pop si
jc _mcgnu6 ;exit if error
cmp BYTE [si], '-' ;check if negative
jne _mcgnu5 ;skip if not
neg ax ;make it negative
_mcgnu5 clc
_mcgnu6 ret
ENDP
;========================================
; Process a token.
;
; In: SI= token buffer; DI= input record.
;
; Out: CY= set if error.
_mac_Token PROC NEAR
call _mac_GetNumber
jc _mctok1
call _mac_Number
ret
;--- check if compiled token
_mctok1 mov ax, OFFSET _mac_Compiled
call _mac_Search
jc _mctok2
call ax
ret
;--- check if standard token
_mctok2 mov ax, OFFSET _mac_Standard
call _mac_Search
jc _mctok3
call _mac_Code
ret
;--- check if user symbol
_mctok3 mov ax, OFFSET MacUsr
call _mac_Search
jc _mctok4
call _mac_External
ret
;--- must be symbol, make a reference
_mctok4 call _mac_Reference
ret
ENDP
;========================================
; Allocate macro memory.
;
; In: AX= size of code table; BX= size of
; stack; CX= size of symbol table.
;
; Out: CY= set of not enough memory.
MacAll PROC NEAR
mov _mac_symsiz, cx ;save size, do not allocate
;--- allocate code and stack segments
push bx
call MemAll ;allocate
mov _mac_codseg, ax ;save segment
mov _mac_codsiz, dx ;save size
pop ax
jc _mcall1
call MemAll ;allocate
mov _mac_stkseg, ax ;save segment
mov _mac_stksiz, dx ;save size
_mcall1 ret
ENDP
;========================================
; Release macro memory.
MacRel PROC NEAR
mov ax, _mac_symseg
or ax, ax
jz _mcrel1
call MemRel ;release symbol segment
_mcrel1 mov ax, _mac_stkseg
call MemRel ;release stack segment
mov ax, _mac_codseg
call MemRel ;release code segment
ret
ENDP
;========================================
; Load and compile a macro file.
;
; In: AX= file name.
;
; Out: CY= set if error; AX= result code
; if error.
MacCom PROC NEAR
push di
push si
push bp
StkAll di, BUFFER_RECORD ;buffer record
StkAll si, MACRO_TOKEN ;token buffer
mov dx, ax
cmp _mac_level, 0 ;check if nest level zero
jne _mccom1 ;jump if so
mov _mac_symptr, 0 ;reset symbol table pointer
mov ax, _mac_symsiz ;reset fixup table pointer
mov _mac_fixptr, ax ;
mov _mac_codptr, 0 ;reset code pointer
mov _mac_undlen, 0 ;reset undefined symbol
mov _mac_undoff, 0 ;
;--- allocate symbol table
_mccom1 cmp _mac_symseg, 0 ;check if already allocated
jnz _mccom2
push dx
mov bp, MACRO_MEMORY ;potential error
mov ax, _mac_symsiz
call MemAll ;allocate
mov _mac_symsiz, dx ;save adjusted size
pop dx
jc _mccom8 ;jump if error
mov _mac_symseg, ax ;save it
;--- open file
_mccom2 push dx
mov ax, 1024
mov bx, di
call BufAll ;allocate buffer
pop ax
jc _mccom7
mov bp, MACRO_FILE ;potential error
mov bx, di
mov cl, BUFFER_READ
call BufOpn ;open buffer
jc _mccom6 ;exit if error
;--- start up code
cmp _mac_level, 0 ;check if nest level zero
jne _mccom4 ;skip startup code if not
mov ax, OFFSET _mac_Startup
call _mac_Code ;store startup code
jc _mccom5 ;jump if error
jmps _mccom4 ;enter loop
;--- loop for each token
_mccom3 call _mac_Token ;process token
mov bp, ax ;potential error
jc _mccom5 ;jump if error
_mccom4 mov ax, si
mov cx, MACRO_TOKEN
mov bx, di
call GetTok ;get next token
jc _mccom9 ;jump if error
or ax, ax ;check if token returned
jnz _mccom3 ;loop back if so
;--- process fixups
sub bp, bp ;no error yet
cmp _mac_level, 0 ;check nest level
jne _mccom5 ;skip fixups if not 0
call _mac_Fixups ;perform fixups
mov bp, ax ;potential error
jc _mccom5 ;jump if error
call MacRes ;reset execution
sub bp, bp ;no errors
;---- close file
_mccom5 mov bx, di
call BufClo ;close buffer
_mccom6 mov bx, di
call BufRel ;release buffer
_mccom7 cmp _mac_level, 0 ;check nest level
jne _mccom8 ;skip deallocate if not zero
cmp MacBug, 0 ;check if preserve symbol table
jne _mccom8 ;skip release if so
mov ax, _mac_symseg
call MemRel ;release symbol table
mov _mac_symseg, 0 ;zero segment
_mccom8 StkRel BUFFER_RECORD,MACRO_TOKEN ;fix stack
mov ax, bp ;return error code in AX
sub dx, dx ;zero
sub dx, ax ;set carry if error
pop bp
pop si
pop di
ret
;--- error reading token
_mccom9 mov bp, MACRO_LONGTOK
or ax, ax
jz _mccom5
mov bp, MACRO_FILE
jmps _mccom5
ENDP
;========================================
; Reset the macro execution.
MacRes PROC NEAR
mov _mac_codsav, OFFSET _mcstar ;entry point
mov ax, _mac_codsiz ;reset return pointer
dec ax
dec ax
mov _mac_retsav, ax
mov ax, _mac_stksiz ;reset stack
mov _mac_stksav, ax
ret
ENDP
;========================================
; Run a loaded macro.
;
; Out: CY= set if macro BREAK, otherwise
; macro terminated.
MacRun PROC NEAR
push di ;used in macro code
push si
push bp ;used in macro code
;--- save stack
mov ax, ss
mov _mac_oldseg, ax
mov _mac_oldoff, sp
;--- switch to new stack
cli
mov ax, _mac_stkseg
mov ss, ax
mov sp, _mac_stksav
sti
;--- transfer to routine
mov ax, _mac_codsav ;entry point
mov si, _mac_retsav ;return pointer
mov ds, _mac_codseg ;segment
seg es
call _mac_start ;enter code
push es
pop ds ;restore data segment
;--- save state
mov _mac_codsav, ax ;entry point
mov _mac_retsav, si ;return pointer
mov _mac_stksav, sp ;stack location
jc _mcrun1 ;jump if BREAK
sub ax, ax ;save QUIT flag in AX
;--- fix stack
_mcrun1 cli
mov dx, _mac_oldseg
mov ss, dx
mov sp, _mac_oldoff
sti
;--- finished
sub dx, dx
sub dx, ax ;set carry if BREAK
pop bp
pop si
pop di
ret
_mac_oldseg DW ? ;original stack segment
_mac_oldoff DW ? ;original stack offset
ENDP
;========================================
; Load the top stack item from an
; external routines.
;
; Out: AX= top item; DX= code/data
; segment.
MacLoa PROC NEAR
push si
push ds
mov ax, _mac_stkseg
mov si, _mac_stksav2
mov ds, ax
cld
lodsw
xchg ax, [si]
pop ds
mov _mac_stksav2, si
mov dx, _mac_codseg
pop si
ret
ENDP
;========================================
; Store the top stack item from an
; external routines.
;
; In: AX= top item.
MacSto PROC NEAR
push si
push ds
mov dx, _mac_stkseg
mov si, _mac_stksav2
mov ds, dx
xchg ax, [si]
dec si
dec si
mov [si], ax
pop ds
mov _mac_stksav2, si
pop si
ret
ENDP
_macro1_end